package org.aldar.bquest.logic.controller.level;

import android.content.Intent;
import android.util.Log;
import org.aldar.bquest.constants.IConstants;
import org.aldar.bquest.constants.LandscapeType;
import org.aldar.bquest.entity.TileSprite;
import org.aldar.bquest.entity.effect.ParticleUtil;
import org.aldar.bquest.entity.pool.TilesPool;
import org.aldar.bquest.logic.TilesGameCycle;
import org.aldar.bquest.logic.controller.board.AfterMatchProcessor;
import org.aldar.bquest.logic.controller.board.TouchAndMoveController;
import org.aldar.bquest.logic.controller.entity.TileBoard;
import org.aldar.bquest.logic.controller.env.CloudController;
import org.aldar.bquest.logic.controller.player.ManaAndPointsController;
import org.aldar.bquest.profile.GameProfile;
import org.aldar.bquest.profile.LevelProfile;
import org.aldar.bquest.resources.ResourceManager;
import org.aldar.bquest.screens.LevelMapScreen;
import org.aldar.bquest.screens.MainBoardScreen;
import org.aldar.bquest.util.CustomButtonSprite;
import org.aldar.bquest.util.Logger;
import org.aldar.bquest.util.TestUtil;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.entity.Entity;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.*;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.input.touch.TouchEvent;
import org.andengine.util.modifier.IModifier;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * User: Daria
 * Date: 6/8/13 8:30 PM
 */
public class LevelController implements IConstants {

    private static LevelDef currentLevel = null;

    private static Text levelText = null;

    private static LevelState currentLevelState = LevelState.PREPARE;

    private static Logger LOG = new Logger(LevelController.class);

    private static LevelController lc;

    TimeLine tl;

    public LevelController() {
        tl = new TimeLine();
        lc = this;
    }

    public enum LevelState {
        PREPARE,
        PROGRESS,
        FINISHED,
        FAILED,
        NONE
    }

    public static LevelController getInstance() {
        return lc;
    }

    public static TimeLine getTimeLine() {
        return lc.tl;
    }

    public void initLevel() {
        GameProfile.setCurrentLevelProfile(new LevelProfile());
        AfterMatchProcessor.resetState();
        TileBoard.resetState();
        TouchAndMoveController.resetLocks();
        setCurrentLevelState(LevelState.PREPARE);
        currentLevel = LevelDefinition.getLevels()[GameProfile.selectedLevelAreaIndex].getAreaLevels().get(GameProfile.selectedLevelIndex);
        //updateLevelNumberText();
//        showStartLevelButton();
        tl.initLevel(currentLevel);
//        initSyncWaterTiles();
        GameProfile.setCurrentLevel(currentLevel);
        //FIXME Test level numbers when level fails etc
        //GameProfile.setSelectedLevelNumber(0);
        TileBoard.initTiles(true);
        GameProfile.getTutorial(MainBoardScreen.getmSQLiteHelper()).showTutorialForLevel(currentLevel);
    }

    private void initSyncWaterTiles() {
        List<TileSprite> waterTiles = new LinkedList<TileSprite>();
        for (int i = 0; i < 20; i++) {
            waterTiles.add(TilesPool.getSpriteForStyle(LandscapeType.WATER, 0, 0));
        }
        for (TileSprite tile : waterTiles) {
            TilesPool.pushToStack(tile);
        }
    }

    private static void updateLevelNumberText() {
        if (levelText != null) {
            levelText.detachSelf();
        }
        levelText = new Text(20, CAMERA_HEIGHT - 30, ResourceManager.getInstance().getmFont(), "Area: " + GameProfile.selectedLevelAreaIndex + ", level " + GameProfile.selectedLevelIndex, 100, MainBoardScreen.getScm().getVertexBufferObjectManager());
        levelText.setAnchorCenter(0, 0);
        MainBoardScreen.getScm().getTestLayer().attachChild(levelText);
    }

    public void onLevelStarted() {
        //MainBoardScreen.getScm().getTestLayer().detachChild(startLevelCurtain);
        //MainBoardScreen.getScm().getMainScene().unregisterTouchArea(startLevelCurtain);
        //TimeController.startLevel();
//        CloudController cloudController = new CloudController(new CloudSettings(60, 1, 3, 20));
        CloudController cloudController = new CloudController(null);
//        TouchAndMoveController.unlockTouchActions();
        TilesGameCycle.getInstance().setGameRunning(true);
        TilesGameCycle.getInstance().resetToWaitingSwap();
        setCurrentLevelState(LevelState.PROGRESS);
    }

    public static LevelDef getCurrentLevel() {
        return currentLevel;
    }

    public static LevelState getCurrentLevelState() {
        return currentLevelState;
    }

    public void setCurrentLevelState(LevelState currentLevelState) {
        TestUtil.getInstance().updateText("level state", currentLevelState.name());
        LevelController.currentLevelState = currentLevelState;
    }

    public void onLevelCompleted() {
        MainBoardScreen.getScm().getMainScene().registerUpdateHandler(new TimerHandler(0.1f, new ITimerCallback() {
            @Override
            public void onTimePassed(TimerHandler pTimerHandler) {
                MainBoardScreen.getInstance().getGameSound().stopMainLoopSound();
                MainBoardScreen.getInstance().getGameSound().stopTicTacSound();
                ManaAndPointsController.getInstance().stopBlinking();
            }
        }));
        MainBoardScreen.getScm().getMainScene().registerUpdateHandler(new TimerHandler(0.3f, new ITimerCallback() {
            @Override
            public void onTimePassed(TimerHandler pTimerHandler) {
                MainBoardScreen.getInstance().getGameSound().playLevelCompletedSound();
            }
        }));

        Map<Integer, Integer[]> finishedLevels = GameProfile.getAllFinishedLevels(MainBoardScreen.getmSQLiteHelper());
        Integer levelKey = LevelDefinition.getLevelKey(GameProfile.selectedLevelAreaIndex, GameProfile.selectedLevelIndex);
        Integer[] levelResults = finishedLevels.get(levelKey);

        //add newly earned money to total money
        int newTotalPoints = GameProfile.getTotalAchievedPoints(MainBoardScreen.getmSQLiteHelper()) + GameProfile.getCurrentLevelProfile().getPointsAchieved();
        GameProfile.setTotalAchievedPoints(newTotalPoints, MainBoardScreen.getmSQLiteHelper());

        int newTotalFame = GameProfile.getTotalFame(MainBoardScreen.getmSQLiteHelper());

        int levelFameToSave = 0;
        GameProfile.getCurrentLevelProfile().getPerformedConcerts();
        int levelScoreToSave = 0;
        GameProfile.getCurrentLevelProfile().getPointsAchieved();

        boolean newBestScore = false;

        //add newly earned fame to total fame / level Fame if its more
        if (levelResults != null) {
            levelFameToSave = levelResults[1];
            levelScoreToSave = levelResults[0];
            //new best score
            if (GameProfile.getCurrentLevelProfile().getPointsAchieved() > levelResults[0]) {
                levelScoreToSave = GameProfile.getCurrentLevelProfile().getPointsAchieved();
                newBestScore = true;
            }
            //new best concerts
            if (GameProfile.getCurrentLevelProfile().getPerformedConcerts() > levelResults[1]) {
                levelFameToSave = GameProfile.getCurrentLevelProfile().getPerformedConcerts();
                // add fame difference to total fame!
                newTotalFame += (levelFameToSave - levelResults[1]);
            }
        } else {
            levelFameToSave = GameProfile.getCurrentLevelProfile().getPerformedConcerts();
            levelScoreToSave = GameProfile.getCurrentLevelProfile().getPointsAchieved();
            //add all achieved fame from current level
            newTotalFame += levelFameToSave;
        }
        GameProfile.setTotalFame(newTotalFame, MainBoardScreen.getmSQLiteHelper());

        GameProfile.saveFinishedLevel(levelKey, levelScoreToSave, levelFameToSave, MainBoardScreen.getmSQLiteHelper());

        //define next area and level to show
        int lastUnlockedAreaIndex = GameProfile.getLastUnlockedAreaIndex(MainBoardScreen.getmSQLiteHelper());
        int finishedLevelsInLastArea = GameProfile.getAllFinishedLevelsForArea(lastUnlockedAreaIndex, MainBoardScreen.getmSQLiteHelper()).size();
        int totalLevelsInLastArea = LevelDefinition.getLevels()[lastUnlockedAreaIndex].getAreaLevels().size();
        Log.i("aldar", "last unlocked area: " + lastUnlockedAreaIndex + " fin lev " + finishedLevels + " total lev " + totalLevelsInLastArea);
        //area completed!!! show popup to unlock next area in level map
        if (totalLevelsInLastArea == finishedLevelsInLastArea) {
            Log.i("aldar", "showing next locked area!!");
            //if last unlocked area is finished -> show next

            //showLevelResults(newBestScore, lastUnlockedAreaIndex + 1, null);
            // always center the map on the current area
            showLevelResults(newBestScore, GameProfile.selectedLevelAreaIndex, null);
        } else {
            //last unlocked area not finished -> show last unlocked
            Log.i("aldar", "showing last unlocked area!!");
            //showLevelResults(newBestScore, lastUnlockedAreaIndex, null);
            // always center the map on the current area
            showLevelResults(newBestScore, GameProfile.selectedLevelAreaIndex, null);
        }
    }

    public void goToLevelMapScreen(Integer areaToHighlight, Integer levelToHighlight) {
        Intent intent = new Intent();
        LevelMapScreen.areaToHighlightAtStart = areaToHighlight;
        LevelMapScreen.levelToHighlightAtStart = levelToHighlight;
        intent.setClass(MainBoardScreen.screenInstance.getApplicationContext(), LevelMapScreen.class);
        MainBoardScreen.screenInstance.startActivity(intent);
        MainBoardScreen.screenInstance.finish();
    }

    public void restartLevel() {
        Intent intent = new Intent();
        intent.setClass(MainBoardScreen.screenInstance.getApplicationContext(), MainBoardScreen.class);
        MainBoardScreen.screenInstance.startActivity(intent);
        MainBoardScreen.screenInstance.finish();

    }

    public void onLevelFailed() {
        MainBoardScreen.getScm().setBgTouchAreas(false, true);
        MainBoardScreen.getScm().getMainScene().registerUpdateHandler(new TimerHandler(0.1f, new ITimerCallback() {
            @Override
            public void onTimePassed(TimerHandler pTimerHandler) {
                MainBoardScreen.getInstance().getGameSound().stopMainLoopSound();
                MainBoardScreen.getInstance().getGameSound().stopTicTacSound();
                ManaAndPointsController.getInstance().stopBlinking();
            }
        }));
        MainBoardScreen.getScm().getMainScene().registerUpdateHandler(new TimerHandler(0.3f, new ITimerCallback() {
            @Override
            public void onTimePassed(TimerHandler pTimerHandler) {
                MainBoardScreen.getInstance().getGameSound().playLevelFailedSound();
            }
        }));

        //MainBoardScreen.getInstance().prepareBanner();
        Sprite levelFailedBg = new Sprite(0, 0, ResourceManager.getInstance().getLevelFailedBgTextureRegion(), MainBoardScreen.getScm().getVertexBufferObjectManager()) {
            @Override
            public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
                return true;
            }
        };
        levelFailedBg.setAnchorCenter(0, 0);

        AnimatedSprite fireInHand = new AnimatedSprite(CAMERA_WIDTH - 125, CAMERA_HEIGHT / 2, ResourceManager.getInstance().getFireOnTileRegion(), MainBoardScreen.getScm().getVertexBufferObjectManager());
        fireInHand.animate(new long[]{50, 50, 50, 50, 50, 50, 50, 50, 50}, new int[]{8, 7, 6, 5, 4, 3, 2, 1, 0}, true);
        fireInHand.setAnchorCenter(0, 0);
        fireInHand.setScale(2f);

        Sprite impFinger = TilesPool.getEntityForTexture(ResourceManager.getInstance().getImpFinger());
        impFinger.setAnchorCenter(0, 0);
        impFinger.setPosition(CAMERA_WIDTH - 130, CAMERA_HEIGHT / 2 - 20);

        MainBoardScreen.getScm().getTutorialLayer().attachChild(levelFailedBg);
        MainBoardScreen.getScm().getTutorialLayer().attachChild(fireInHand);
        MainBoardScreen.getScm().getTutorialLayer().attachChild(impFinger);

        CustomButtonSprite buttonYesTryAgain = new CustomButtonSprite(CAMERA_WIDTH / 2 - 50, 125, MainBoardScreen.getScm().getButtonYesTextureRegion().getTextureRegion(0),
                MainBoardScreen.getScm().getButtonYesTextureRegion().getTextureRegion(1),
                MainBoardScreen.getScm().getVertexBufferObjectManager(),
                new CustomButtonSprite.OnClickListener() {
                    @Override
                    public void onClick(CustomButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {

                        MainBoardScreen.getInstance().displayInterstitial(new Runnable() {
                            @Override
                            public void run() {
                                restartLevel();
                            }
                        });
                    }
                }
        );

        MainBoardScreen.getScm().getTutorialLayer().attachChild(buttonYesTryAgain);
        MainBoardScreen.getScm().getMainScene().registerTouchArea(buttonYesTryAgain);

        CustomButtonSprite buttonNoTryAgain = new CustomButtonSprite(CAMERA_WIDTH / 2 + 50, 125, MainBoardScreen.getScm().getButtonNoTextureRegion().getTextureRegion(0),
                MainBoardScreen.getScm().getButtonNoTextureRegion().getTextureRegion(1),
                MainBoardScreen.getScm().getVertexBufferObjectManager(),
                new CustomButtonSprite.OnClickListener() {
                    @Override
                    public void onClick(CustomButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {

                        MainBoardScreen.getInstance().displayInterstitial(new Runnable() {
                            @Override
                            public void run() {
                                goToLevelMapScreen(GameProfile.selectedLevelAreaIndex, null);
                            }
                        });
                    }
                }
        );
        MainBoardScreen.getScm().getTutorialLayer().attachChild(buttonNoTryAgain);
        MainBoardScreen.getScm().getMainScene().registerTouchArea(buttonNoTryAgain);
        MainBoardScreen.getScm().getMainScene().registerTouchArea(levelFailedBg);

        reveal(0.5f, levelFailedBg);

    }

    private void reveal(float duration, Entity entity) {
        entity.registerEntityModifier(new AlphaModifier(duration, 0, 1));
    }

    public void showLevelResults(boolean newBestScore, final Integer areaToHighlightOnContinue, final Integer levelToHighlightOnContinue) {
        MainBoardScreen.getScm().setBgTouchAreas(false, true);

        Sprite levelResultsBg = new Sprite(0, 0, ResourceManager.getInstance().getLevelCompletedBgTextureRegion(), MainBoardScreen.getScm().getVertexBufferObjectManager());

        levelResultsBg.setAnchorCenter(0, 0);
        MainBoardScreen.getScm().getTutorialLayer().attachChild(levelResultsBg);
        CustomButtonSprite buttonContinue = new CustomButtonSprite(
                CAMERA_WIDTH / 2 + 70, 125, ResourceManager.getInstance().getButtonContinuePressedTextureRegion().getTextureRegion(0),
                ResourceManager.getInstance().getButtonContinuePressedTextureRegion().getTextureRegion(1),
                MainBoardScreen.getScm().getVertexBufferObjectManager(),
                new CustomButtonSprite.OnClickListener() {
                    @Override
                    public void onClick(CustomButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {

                        MainBoardScreen.getInstance().displayInterstitial(new Runnable() {
                            @Override
                            public void run() {
                                goToLevelMapScreen(areaToHighlightOnContinue, levelToHighlightOnContinue);
                            }
                        });
                    }
                }
        );

        MainBoardScreen.getScm().getTutorialLayer().attachChild(buttonContinue);
        MainBoardScreen.getScm().getMainScene().registerTouchArea(buttonContinue);

        CustomButtonSprite buttonLeftAction = new CustomButtonSprite(
                CAMERA_WIDTH / 2 - 70, 125, ResourceManager.getInstance().getButtonRateApp().getTextureRegion(0),
                ResourceManager.getInstance().getButtonRateApp().getTextureRegion(1),
                MainBoardScreen.getScm().getVertexBufferObjectManager(),
                new CustomButtonSprite.OnClickListener() {
                    @Override
                    public void onClick(CustomButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {

                        MainBoardScreen.getInstance().rateAppButtonAction();
                    }
                }
        );
        MainBoardScreen.getScm().getTutorialLayer().attachChild(buttonLeftAction);
        MainBoardScreen.getScm().getMainScene().registerTouchArea(buttonLeftAction);
        showLevelAchievements();
    }

    private void showLevelAchievements() {
        String totalMoneyText = "" + GameProfile.getCurrentLevelProfile().getPointsAchieved();
        final Text totalMoney = new Text(CAMERA_WIDTH / 2 + 85, 196, ResourceManager.getInstance().getFontTrebuchetBoldGold(), totalMoneyText, MainBoardScreen.getScm().getVertexBufferObjectManager());
        MainBoardScreen.getScm().getTutorialLayer().attachChild(totalMoney);

        int collectedJewels = GameProfile.getCurrentLevelProfile().getPerformedConcerts();
        String collectedJewelsText = "" +
                (collectedJewels == 0 ?
                        "-" : collectedJewels);
        final Text collectedJewelsSprite = new Text(CAMERA_WIDTH / 2 - 85, 196, ResourceManager.getInstance().getFontTrebuchetBoldGold(), collectedJewelsText, MainBoardScreen.getScm().getVertexBufferObjectManager());
        MainBoardScreen.getScm().getTutorialLayer().attachChild(collectedJewelsSprite);

        for (int i = 0; i < collectedJewels; i++) {
            float x = 100 + 70 * i;
            float y = CAMERA_HEIGHT - 200;
            float scale = 1f;

            if (collectedJewels == 1
                    || collectedJewels == 3
                    || collectedJewels == 5) {
                if (i == 0) {
                    x = CAMERA_WIDTH / 2;
                    y = CAMERA_HEIGHT - 75;
                    scale = 2f;
                } else if (i == 1) {
                    x = CAMERA_WIDTH / 2 - 95;
                    y = CAMERA_HEIGHT - 100;
                    scale = 1.8f;
                } else if (i == 2) {
                    x = CAMERA_WIDTH / 2 + 95;
                    y = CAMERA_HEIGHT - 100;
                    scale = 1.8f;
                } else if (i == 3) {
                    x = CAMERA_WIDTH / 2 - 170;
                    y = CAMERA_HEIGHT - 150;
                    scale = 1.5f;
                } else if (i == 4) {
                    x = CAMERA_WIDTH / 2 + 170;
                    y = CAMERA_HEIGHT - 150;
                    scale = 1.5f;
                }
            } else if (collectedJewels == 2 ||
                    collectedJewels == 4) {
                if (i == 0) {
                    x = CAMERA_WIDTH / 2 - 50;
                    y = CAMERA_HEIGHT - 80;
                    scale = 2f;
                } else if (i == 1) {
                    x = CAMERA_WIDTH / 2 + 50;
                    y = CAMERA_HEIGHT - 80;
                    scale = 2f;
                } else if (i == 2) {
                    x = CAMERA_WIDTH / 2 - 130;
                    y = CAMERA_HEIGHT - 110;
                    scale = 1.8f;
                } else if (i == 3) {
                    x = CAMERA_WIDTH / 2 + 130;
                    y = CAMERA_HEIGHT - 110;
                    scale = 1.8f;
                }
            }

            final Sprite effectStar = TilesPool.getEntityForTexture(ResourceManager.getInstance().getEffectSkill());
            MainBoardScreen.getScm().getTutorialLayer().attachChild(effectStar);
            effectStar.setPosition(x, y);
            effectStar.setScale(scale * 0.4f);
            effectStar.registerEntityModifier(
                    new LoopEntityModifier(
                            new RotationAtModifier(5f, 0, 360, 0.5f, 0.5f)));

            final Sprite jewelParticle = TilesPool.getEntityForTexture(ResourceManager.getInstance().getJewelParticle());
            jewelParticle.setPosition(x, y);
            jewelParticle.setScale(scale);
            MainBoardScreen.getScm().getTutorialLayer().attachChild(jewelParticle);
            jewelParticle.registerEntityModifier(
                    new LoopEntityModifier(
                            new SequenceEntityModifier(
                                    new RotationAtModifier(1.5f, -20, 20, 0.5f, 0.5f),
                                    new RotationAtModifier(1.5f, 20, -20, 0.5f, 0.5f))));
        }
        final Entity coinsEntity = new Entity();
        MainBoardScreen.getScm().getTutorialLayer().attachChild(coinsEntity);
        coinsEntity.registerEntityModifier(new LoopEntityModifier(
                new DelayModifier(0.5f, new IEntityModifier.IEntityModifierListener() {
                    @Override
                    public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                        ParticleUtil.makeCoinPath(CAMERA_WIDTH / 2 + 35, CAMERA_HEIGHT / 2 + 225, CAMERA_WIDTH / 10 * new Random().nextInt(10), -100, 1, coinsEntity);
                    }

                    @Override
                    public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                    }
                })
        ));


    }

}
